package com.fm.lockhart.listener;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.CreateCollectionOptions;
import org.bson.Document;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class RequestListener implements ServletRequestListener, ServletContextListener {
	private static final String task = "Lockhart_WebRequestListener";

	private ThreadLocal<UUID> ids = new ThreadLocal<>();
	private MongoCollection<Document> starting;
	private MongoCollection<Document> finished;
	private MongoCollection<Document> dealfail;
	protected MongoClient client;

	protected abstract void initMongo();

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		initMongo();
		MongoDatabase db = client.getDatabase("LOGGER");
		Iterable<String> it = db.listCollectionNames();
		Set<String> names = new HashSet<>();
		for (String name : it) {
			names.add(name);
		}
		if (!names.contains("finished_task")) {
			db.createCollection("finished_task",
				new CreateCollectionOptions().capped(true).sizeInBytes(1073741824).maxDocuments(10000));
		}
		if (!names.contains("dealfail_task")) {
			db.createCollection("dealfail_task",
				new CreateCollectionOptions().capped(true).sizeInBytes(1073741824).maxDocuments(10000));
		}
		starting = db.getCollection("starting_task");
		finished = db.getCollection("finished_task");
		dealfail = db.getCollection("dealfail_task");

		ListenerTasks.appendTask((request, response) -> request.setAttribute(task, response));
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		client.close();
	}

	@Override
	public void requestInitialized(final ServletRequestEvent sre) {
		HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
		UUID id = ids.get();

		if (id != null) {
			Document q = new Document("_id", id.toString());
			Document doc = starting.findOneAndDelete(q);
			dealfail.insertOne(doc);
		}

		id = UUID.randomUUID();
		Document task = new Document();
		task.put("_id", id.toString());
		task.put("thread", Thread.currentThread().toString());
		task.put("request", new Document()
				.append("method", request.getMethod())
				.append("url", request.getRequestURI())
				.append("param", request.getParameterMap())
				.append("client", new Document()
						.append("host", request.getRemoteAddr())
						.append("port", request.getRemotePort())
				)
		);
		task.put("createTime", System.currentTimeMillis());
		starting.insertOne(task);
		ids.set(id);
	}

	@Override
	public void requestDestroyed(final ServletRequestEvent sre) {
		HttpServletResponse servletResponse = (HttpServletResponse) sre.getServletRequest().getAttribute(task);
		UUID id = ids.get();
		Document q = new Document("_id", id.toString());
		Document task = starting.findOneAndDelete(q);
		task.put("finishTime", System.currentTimeMillis());
		task.put("costTime", task.getLong("finishTime") - task.getLong("createTime"));
		task.put("response", new Document().append("code", servletResponse.getStatus()));
		finished.insertOne(task);
		ids.remove();
	}
}
